﻿using Sunny.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace SmartMotion.Core.Tools
{
    public partial class FrmConstructor : UIForm
    {
        #region 私有字段

        private readonly Constructor _constructor;
        private List<Type> _types;
        private ConstructorInfo[] _constructorInfos;
        private readonly List<string> _paraTypes;
        private readonly List<string> _paraNames;

        private List<string> _dllList;
        private List<Type> _allType;
        private List<Type> _searchType;
        private List<MethodInfo> _allmethods;
        private List<MethodInfo> _searchMethods;

        #endregion 私有字段

        public FrmConstructor(Constructor constructor)
        {
            _constructor = constructor;
            _paraTypes = new List<string>();
            _paraNames = new List<string>();
            InitializeComponent();
        }

        private void FrmConstructor_Load(object sender, EventArgs e)
        {
            RefreshDll();
        }

        private void RefreshDll(bool loadAll = true)
        {
            _dllList = new List<string>();
            var files = Directory.GetFiles(Environment.CurrentDirectory, "*.dll");
            lsbDll.Items.Clear();
            foreach (var file in files)
            {
                lsbDll.Items.Add(Path.GetFileName(file));
                _dllList.Add(Path.GetFileName(file));
            }

            #region 加载上一次的配置

            int index = lsbDll.Items.IndexOf(_constructor.Dll);
            lsbDll.SelectedIndex = index;
            var curDll = Assembly.LoadFile(Environment.CurrentDirectory + "\\" + lsbDll.SelectedItem);
            _types = curDll.GetTypes().ToList();

            if (_types == null)
            {
                return;
            }
            foreach (var type in _types)
            {
                if (type.FullName == _constructor.TypeName)
                {
                    lsbTypes.SelectedItem = type;
                    break;
                }
            }

            foreach (var constructorInfo in _constructorInfos)
            {
                if (constructorInfo.Name == _constructor.MethodName)
                {
                    if (constructorInfo.GetParameters().Length == _constructor.ParaTypes.Count)
                    {
                        lstMethod.SelectedItem = constructorInfo;
                        break;
                    }
                }
            }

            txtName.Text = _constructor.ItemName;

            #endregion 加载上一次的配置
        }

        private void txtSearchDll_TextChanged(object sender, EventArgs e)
        {
            lsbDll.Items.Clear();
            string txtSearch = txtSearchDll.Text;
            foreach (var dll in _dllList.Where(dll => dll.ToLower().Contains(txtSearch.ToLower())))
            {
                lsbDll.Items.Add(dll);
            }
        }

        private void lstDll_SelectedIndexChanged(object sender, EventArgs e)
        {
            string fileName = Environment.CurrentDirectory + "\\" + lsbDll.SelectedItem;
            var curDll = Assembly.LoadFile(fileName);
            var types = curDll.GetTypes();
            _allType = types.ToList();
            _searchType = types.ToList();
            var bs = new BindingSource();
            bs.DataSource = _searchType;
            lsbTypes.DataSource = bs;
            lsbTypes.DisplayMember = "Name";
        }

        private void txtSearchType_TextChanged(object sender, EventArgs e)
        {
            string txtSearch = txtSearchType.Text;
            _searchType.Clear();
            foreach (var type in _allType.Where(type => type.Name.ToLower().Contains(txtSearch)))
            {
                _searchType.Add(type);
            }
            var bs = new BindingSource();
            bs.DataSource = _searchType;
            lsbTypes.DataSource = bs;
            lsbTypes.DisplayMember = "Name";
        }

        private void lstTypes_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lsbTypes.SelectedItem is Type type)
            {
                _constructorInfos = type.GetConstructors();
                BindingSource bs = new BindingSource();
                bs.DataSource = _constructorInfos;
                lstMethod.DataSource = bs;
                _constructor.Description = $"{type.FullName}";
            }
        }

        private void lstMethod_SelectedIndexChanged(object sender, EventArgs e)
        {
            var ci = lstMethod.SelectedItem as ConstructorInfo;
            if (ci == null) return;

            var parameters = ci.GetParameters();
            _paraTypes.Clear();
            _paraNames.Clear();
            foreach (var parameterInfo in parameters)
            {
                _paraNames.Add(parameterInfo.Name);
                _paraTypes.Add(parameterInfo.ParameterType.FullName);
            }
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            RefreshDll(true);
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (txtName.Text.Length == 0)
            {
                ShowErrorDialog("请输入一个名称");
                return;
            }
            if (lsbDll.SelectedItem == null) return;
            if (lsbTypes.SelectedItem == null) return;
            if (lstMethod.SelectedItem == null) return;
            _constructor.ItemName = txtName.Text;
            _constructor.Dll = lsbDll.SelectedItem.ToString();
            _constructor.TypeName = (lsbTypes.SelectedItem as Type)?.FullName;
            var ci = lstMethod.SelectedItem as ConstructorInfo;
            _constructor.MethodName = (ci)?.Name;
            _constructor.IsStatic = true;
            _constructor.Parms.Clear();
            _constructor.ParaNames.Clear();
            _constructor.ParaTypes.Clear();
            _constructor.ReturnType = typeof(object).FullName;
            _paraNames.ForEach(item => _constructor.ParaNames.Add(item));
            _paraTypes.ForEach(item => _constructor.ParaTypes.Add(item));
            for (int i = 0; i < _paraTypes.Count; i++)
            {
                _constructor.Parms.Add(new MethodParms() { Name = _paraNames[i], Type = _paraTypes[i] });
            }

            _constructor.InnerConstructor = null;
            DialogResult = DialogResult.OK;
            Close();
        }
    }
}
